package com.mengma.ec.service.impl.portal;

import com.alipay.api.AlipayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mengma.ec.commons.Const;
import com.mengma.ec.commons.ServerResponse;
import com.mengma.ec.dao.*;
import com.mengma.ec.entity.*;
import com.mengma.ec.service.portal.IOrderService;
import com.mengma.ec.util.BigDecimalUtil;
import com.mengma.ec.vo.OrderItemVo;
import com.mengma.ec.vo.OrderVo;
import com.mengma.ec.vo.ShippingVo;
import lombok.extern.java.Log;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Auther: xixi
 * @Date: 2018/9/26 14:47
 * @Description:
 */
@Service("iOrderService")
@Log
public class OrderServiceImpl implements IOrderService{
    private static AlipayTradeService tradeService;

    static {
        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");

        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();

        // 支付宝当面付2.0服务（集成了交易保障接口逻辑）
       // tradeWithHBService = new AlipayTradeWithHBServiceImpl.ClientBuilder().build();

        /** 如果需要在程序中覆盖Configs提供的默认参数, 可以使用ClientBuilder类的setXXX方法修改默认参数 否则使用代码中的默认设置 */
        //monitorService = new AlipayMonitorServiceImpl.ClientBuilder()
       //         .setGatewayUrl("http://mcloudmonitor.com/gateway.do").setCharset("GBK")
        //        .setFormat("json").build();
    }
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private CartMapper cartMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ShippingMapper shippingMapper;

    //1.创建订单
    @Override
    public ServerResponse<OrderVo> create(Integer id, Integer shippingId) {
        //1.收货地址信息（true） 2.需要购买的商品信息（false）

        //1.1通过userId 查询购物车表，条件为选中状态
        List<Cart> cartList = cartMapper.findCartByUserIdAndChecked(id);

        ServerResponse response = this.getCartOrderItem(cartList,id);
        if (!response.isSuccess()){
            return response;
        }

        List<OrderItem> orderItemList = (List<OrderItem>) response.getData();

        //1.2 计算当前需要购物的所有商品的总价
        BigDecimal totalPrice = this.getOrderTotalPrice(orderItemList);

        System.out.println(totalPrice + ">>>>>>>>>>>>>>>>>>");
        //1.3生成订单
        Order order =  this.addOrder(id,shippingId,totalPrice);

        if (order ==null){
            return ServerResponse.createByErrorMessage("生成订单错误！");
        }


        // 拿取 order.getOrderNO
        Long order_no = order.getOrderNo();

        List<OrderItem> newList = new ArrayList<>();

        for (OrderItem orderItem : orderItemList) {
            orderItem.setOrderNo(order_no);
        }

        // 添加 order_item 表数据 （批量添加数据）
        int count = orderItemMapper.batchInsert(orderItemList);
        if (count <= 0) {
            return ServerResponse.createByErrorMessage("新增失败");
        }

        // TODO 1 减少库存 2 清空购物车

        //1. 减少库存
        this.reduceProductStock(orderItemList);

        //2. 清空购物车
        this.cleanCart(cartList);

        //3. 最后 查询数据，并返回该有数据
        OrderVo orderVo = assembleOrderVo(order,orderItemList);

        return ServerResponse.createBySuccess(orderVo);
    }


    /**
     *
     * @param order
     * @param orderItemList
     * @return
     */
    private OrderVo assembleOrderVo(Order order, List<OrderItem> orderItemList) {
        OrderVo orderVo = new OrderVo();

        orderVo.setOrderNo(order.getOrderNo());
        orderVo.setPayment(order.getPayment());
        orderVo.setPaymentType(order.getPaymentType());
//        orderVo.setPaymentTypeDesc(Const.PaymentTypeEnum.codeOf(order.getPaymentType()).getValue());

        orderVo.setPostage(order.getPostage());
        orderVo.setStatus(order.getStatus());
//        orderVo.setStatusDesc(Const.OrderStatusEnum.codeOf(order.getStatus()).getValue());

        orderVo.setShippingId(order.getShippingId());


        // 通过 收货地址ID 查询 收货地址详细信息
        Shipping shipping = shippingMapper.selectByPrimaryKey(order.getShippingId());
        if (shipping != null) {
            orderVo.setReceiverName(shipping.getReceiverName());
            orderVo.setShippingVo(this.assembleShippingVo(shipping));
        }

        orderVo.setPaymentTime("2018-09-27");
        orderVo.setSendTime("2018-09-27");
        orderVo.setEndTime("2018-09-27");
        orderVo.setCreateTime("2018-09-27");
        orderVo.setCloseTime("2018-09-27");

//        orderVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));

        List<OrderItemVo> orderItemVoList = new ArrayList<>();

        for (OrderItem orderItem : orderItemList) {
            OrderItemVo orderItemVo = assembleOrderItemVo(orderItem);
            orderItemVoList.add(orderItemVo);
        }
        orderVo.setOrderItemVoList(orderItemVoList);
        return orderVo;

    }

    /**
     * 通过 orderItem 数据源 ，转换为 VO 显示对象
     * @param orderItem
     * @return
     */
    private OrderItemVo assembleOrderItemVo(OrderItem orderItem) {
        OrderItemVo orderItemVo = new OrderItemVo();
        orderItemVo.setOrderNo(orderItem.getOrderNo());
        orderItemVo.setProductId(orderItem.getProductId());
        orderItemVo.setProductName(orderItem.getProductName());
        orderItemVo.setProductImage(orderItem.getProductImage());
        orderItemVo.setCurrentUnitPrice(orderItem.getCurrentUnitPrice());
        orderItemVo.setQuantity(orderItem.getQuantity());
        orderItemVo.setTotalPrice(orderItem.getTotalPrice());
        return orderItemVo;
    }

    /**
     * 通过说地址详细信息，包装成需要显示的 VO 对象
     * @param shipping
     * @return
     */
    private ShippingVo assembleShippingVo(Shipping shipping) {
        ShippingVo shippingVo = new ShippingVo();
        shippingVo.setReceiverName(shipping.getReceiverName());
        shippingVo.setReceiverAddress(shipping.getReceiverAddress());
        shippingVo.setReceiverProvince(shipping.getReceiverProvince());
        shippingVo.setReceiverCity(shipping.getReceiverCity());
        shippingVo.setReceiverDistrict(shipping.getReceiverDistrict());
        shippingVo.setReceiverMobile(shipping.getReceiverMobile());
        shippingVo.setReceiverZip(shipping.getReceiverZip());
        shippingVo.setReceiverPhone(shippingVo.getReceiverPhone());
        return shippingVo;

    }

    /**
     * 清空购物车
     * @param cartList
     */
    private void cleanCart(List<Cart> cartList) {
        for (Cart cart : cartList) {
            cartMapper.deleteByPrimaryKey(cart.getId());
            //ToDo 判断购物车是否
        }
    }

    /**
     * 减少库存
     * @param orderItemList
     */
    private void reduceProductStock(List<OrderItem> orderItemList) {
        for (OrderItem orderItem : orderItemList) {
            //1. 拿取producId 获取商品详细信息
            Product product = productMapper.selectByPrimaryKey(orderItem.getProductId());
            //2. 减少库存
            product.setStock(product.getStock()-orderItem.getQuantity());
            //3. 更新即可
            int i = productMapper.updateByPrimaryKey(product);
            //TODO 可以完善代码 进行update 是否成功的逻辑判断
        }
        

    }

    /**
     * 生成订单
     * @param id
     * @param shippingId
     * @param totalPrice
     */
    private Order addOrder(Integer id, Integer shippingId, BigDecimal totalPrice) {
        Order order = new Order();
        order.setUserId(id);
        order.setShippingId(shippingId);
        order.setPayment(totalPrice);

        //1. 生成order_no(此值为唯一值)
        long currentTime = System.currentTimeMillis();
        long order_no = currentTime + new Random().nextInt(100);
        order.setOrderNo(order_no);

        //2.设置支付类型
        order.setPaymentType(1);

        //3. 设置运费
        order.setPostage(0);

        //4. 设置状态值 （订单状态:0-已取消-10-未付款，20-已付款，40-已发货，50-交易成功，60-交易关闭）
        order.setStatus(10);

        int insert = orderMapper.insert(order);
        if (insert > 0){
            return order;
        }
        return null;
    }

    /**
     * 通过购物车具体商品list，计算总价格
     * @param orderItemList
     * @return
     */
    private BigDecimal getOrderTotalPrice(List<OrderItem> orderItemList) {
        BigDecimal totalPrice = new BigDecimal("0");
        for (OrderItem orderItem : orderItemList) {
            totalPrice  = BigDecimalUtil.add(totalPrice.doubleValue(), orderItem.getTotalPrice().doubleValue());
        }
        return totalPrice;
    }

    /**
     * 通过购物车选中商品信息，获取包装购物车商品信息List<vo>
     * @param cartList
     * @return
     */
    private ServerResponse getCartOrderItem(List<Cart> cartList ,Integer userId) {

        List<OrderItem> orderItemList = new ArrayList<>();

        //判断购物车是否为空
        if (cartList.size()==0){
            return ServerResponse.createByErrorMessage("购物车为空");
        }

        //1检查购物车具体单个商品的数据（商品的状态（1=在售 2=下架），数量）
        for (Cart cartItem : cartList) {
            OrderItem orderItem = new OrderItem();


            //1.1 通过购物车表 商品id字段查询该商品具体信息
            Product product = productMapper.selectByPrimaryKey(cartItem.getProductId());

            //1.2 通过商品具体信息，判断商品是否在售
            if ( 1 != product.getStatus()){
                return ServerResponse.createByErrorMessage("商品"+product.getName()+"已经下架");
            }

            //1.3 通过商品具体信息，判断购买数量是否等于或小于库存
            if (cartItem.getQuantity() > product.getStock()){
                return ServerResponse.createByErrorMessage("商品"+product.getName()+"库存不足");
            }

            orderItem.setUserId(userId);
            orderItem.setProductId(product.getId());
            orderItem.setProductName(product.getName());
            orderItem.setProductImage(product.getMainImage());
            orderItem.setCurrentUnitPrice(product.getPrice());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(),cartItem.getQuantity()));

            orderItemList.add(orderItem);
        }
        return ServerResponse.createBySuccess(orderItemList);
    }


    @Override
    public ServerResponse get_order_cart_product(Integer id) {
        List<OrderItem> orderItemList = orderItemMapper.selectByUserId(id);
        List<OrderItemVo> orderItemVoList = new ArrayList<>();

        for (OrderItem orderItem : orderItemList) {
            OrderItemVo orderItemVo = assembleOrderItemVo(orderItem);
            orderItemVoList.add(orderItemVo);
        }
        return ServerResponse.createBySuccess(orderItemVoList);
    }

    @Override
    public ServerResponse list(Integer userId, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum,pageSize);
//        List<OrderVo> orderVoList=this.ListDingDan(userId);
        //获取原始数据源
        List<OrderVo> orderVoList=new ArrayList<>();
        List<Order> orders=orderMapper.selectByUserId(userId);
        if (orders.size()==0){
            return ServerResponse.createByErrorMessage("没有数据");
        }
        for (Order order : orders) {
            List<OrderItem> orderItems=orderItemMapper.selectByOrderNo(order.getOrderNo());
            OrderVo orderVo = assembleOrderVo(order, orderItems);
            orderVoList.add(orderVo);
        }
        PageInfo pageInfo = new PageInfo(orders);
        pageInfo.setList(orderVoList);

        return ServerResponse.createBySuccess(pageInfo);
    }

    @Override
    public ServerResponse pay(Integer id, Long orderNo) {

        //判断此订单是否存在（需要他故意订单编号orderNo查询订单详细信息）
        //通过userId和orderNo
        Order order = orderMapper.findByUserIdAndOrderNo(id,orderNo);
        if (order == null){
            return ServerResponse.createByErrorMessage("此订单不存在");
        }
        Map<String,String> map = new HashMap<>();

        //设置orderNo
        map.put("orderNo",String.valueOf(orderNo));

        //支付代码

        // (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
        // 需保证商户系统端不能重复，建议通过数据库sequence生成，
        String outTradeNo = String.valueOf(orderNo);

        // (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
        String subject = "梦码商城扫码支付，订单号："+outTradeNo;

        // (必填) 订单总金额，单位为元，不能超过1亿元
        String totalAmount = order.getPayment().toString();

        // (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
        // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
        String undiscountableAmount = "0";

        // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
        // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        String sellerId = "";

        // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
        String body = "订单："+outTradeNo+"购买商品共："+outTradeNo+"元";

        // 商户操作员编号，添加此参数可以为商户操作员做销售统计
        String operatorId = "test_operator_id";

        // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
        String storeId = "test_store_id";

        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId("2088100200300400500");

        // 支付超时，定义为120分钟
        String timeoutExpress = "120m";

        // 商品明细列表，需填写购买商品详细信息，
        List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();
        List<OrderItem> orderItemList = orderItemMapper.findByUserIdAndOrderNo(id,orderNo);
        for (OrderItem orderItem : orderItemList) {
            // 创建一个商品信息，参数含义分别为商品id（使用国标）、名称、单价（单位为分）、数量，如果需要添加商品类别，详见GoodsDetail
            GoodsDetail goods = GoodsDetail.newInstance(
                    orderItem.getProductId().toString(),
                    orderItem.getProductName(),
                    BigDecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(),new Double(100)).longValue(),
                    orderItem.getQuantity());
            // 创建好一个商品后添加至商品明细列表
            goodsDetailList.add(goods);
        }

        // 创建扫码支付请求builder，设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
                .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
                .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
                .setTimeoutExpress(timeoutExpress)
                .setNotifyUrl("http://2nqjxg.natappfree.cc/order/alipay_callback.do")//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
                .setGoodsDetailList(goodsDetailList);

        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                log.info("支付宝预下单成功: )");

                AlipayTradePrecreateResponse response = result.getResponse();
                dumpResponse(response);

                //核心关键点
                //创建一个文件目录用来保存 支付宝给我们的二维码支付图片
                File folder = new File("D:\\qin\\ec\\zfb_ewm_images");

                //如果这个目录存在 就直接使用
                if (!folder.exists()){
                    //开启可写权限
                    folder.setWritable(true);
                    //创建文件夹
                    folder.mkdir();
                }

                //给我们需要保存的 支付宝支付的二维码图片起名
                String zfFileName = String.format("qr-%s.png",response.getOutTradeNo());

                //给我们需要保存的 支付宝支付的二维码图片设置保存路径
                String path = "D:\\qin\\ec\\zfb_ewm_images";
                String zfFilePath = path + String.format("qr-%s.png",response.getOutTradeNo());

                System.out.println(zfFilePath+"路径！");
                ZxingUtils.getQRCodeImge(response.getQrCode(),256,zfFilePath);
                
            break;

            case FAILED:
       //         log.error("支付宝预下单失败!!!");
                break;

            case UNKNOWN:
          //      log.error("系统异常，预下单状态未知!!!");
                break;

            default:
          //      log.error("不支持的交易状态，交易返回异常!!!");
                break;
        }
        return null;
    }

    @Override
    public ServerResponse checkDataLegal(Map<String, String> params) {

        String orderNo = params.get("out_trade_no");
        Order order = orderMapper.findByOrderNo(orderNo);
        System.out.println(orderNo+"我是获取订单号 ");
        if (order == null) {
            return ServerResponse.createByErrorMessage("么有此订单!");
        }
        //判断此订单是否正常需要支付的订单
        if (order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()) {
            return ServerResponse.createByErrorMessage("订单已支付！");
        }

        //通过支付宝返回的交易状态值来判断用户是否支付成功
        String trade_status = params.get("trade_status");
        log.info(trade_status+"trade_status");
        if (Const.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(trade_status)) {
            order.setPaymentTime(new Date());
            order.setStatus(Const.OrderStatusEnum.PAID.getCode());
            orderMapper.updateByPrimaryKey(order);

            return ServerResponse.createBySuccess();
        }

        return ServerResponse.createByError();
    }

    @Override
    public ServerResponse query_order_pay_status(Integer id, Long orderNo) {
        Order order = orderMapper.selectByUserIdOrderNo(id,orderNo);
        if(order == null){
            return ServerResponse.createByErrorMessage("该用户没有该订单");
        }
        if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
            return ServerResponse.createBySuccess(true);
        }
        return ServerResponse.createByError();
    }

    // 简单打印应答
    private void dumpResponse(AlipayResponse response) {
        if (response != null) {
            log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
                log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                        response.getSubMsg()));
            }
            log.info("body:" + response.getBody());
        }
    }
}
